package com.songyang.blog.shiro;

import cn.hutool.crypto.symmetric.SymmetricAlgorithm;
import cn.hutool.crypto.symmetric.SymmetricCrypto;
import cn.hutool.json.JSONUtil;
import com.songyang.blog.entity.Auth;
import com.songyang.blog.entity.User;
import com.songyang.blog.service.UserService;
import com.songyang.blog.util.RandomStringUtils;
import com.songyang.blog.util.RedisUtil;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Date;

@Component
public class AccountRealm extends AuthorizingRealm {
    @Autowired
    UserService userService;

    @Autowired
    RedisUtil redisUtil;

    @Autowired
    HttpServletResponse response;

    @Override//授权
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {
        User user = (User) principal.getPrimaryPrincipal();//获取当前登录的用户
        if (user != null && user.getId() == 7) {
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
            info.addRole("admin");//给id为7的admin赋予admin角色
            return info;
        }
        return null;
    }

    @Override//认证
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) {
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        User profile = userService.login(token.getUsername(), String.valueOf(token.getPassword()));
        setLoginCookieEncrypt(profile);//加密
//        setLoginCookie(profile);//不加密的
        setLoginTime(token, profile);
        /*
        这里在向cookie写入七天免登陆的时候，不要写用户名和密码，写入Redis生成的id，然后通过这个id去服务器拿用户名和密码
        但是这个方案会造成Redis空间大量使用，需要思考新的解决方案
         */
        return new SimpleAuthenticationInfo(profile, token.getCredentials(), getName());
    }

    public void setLoginCookieEncrypt(User profile) {
        String enJson = "";
        try {
            //user序列化后的json
            Auth auth = new Auth();
            auth.setEmail(profile.getEmail());
            auth.setPassword(profile.getPassword());
            String encodeCookie = JSONUtil.toJsonStr(auth);
            String key = setKeyOnCookieAndRedis();//获取到key
            SymmetricCrypto aes = new SymmetricCrypto(SymmetricAlgorithm.AES, key.getBytes(StandardCharsets.UTF_8));
            byte[] encrypt = aes.encrypt(encodeCookie);//加密之后得到的数组
            enJson = new String(encrypt, StandardCharsets.ISO_8859_1);
//            System.out.println("字符串:" + enJson.length());
            enJson = URLEncoder.encode(enJson, "utf-8");//对字体进行编码
            Cookie cookie = new Cookie("isLogin", enJson);//把对象的json写入cookie
            cookie.setPath("/");
            cookie.setMaxAge(60 * 60 * 24 * 7);
            response.addCookie(cookie);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }

    //不加密方式
    public void setLoginCookie(User profile) {
        String enJson = "";
        try {
            //user序列化后的json
            String encodeCookie = JSONUtil.toJsonStr(profile);
            enJson = URLEncoder.encode(encodeCookie, "UTF-8");//对字体进行编码
            Cookie cookie = new Cookie("isLoginUn", enJson);//把对象的json写入cookie
            cookie.setPath("/");
            cookie.setMaxAge(60 * 60 * 24 * 7);
            response.addCookie(cookie);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }

    //向Redis写入当前用户的登录时间
    public void setLoginTime(UsernamePasswordToken token, User profile) {
        String key = token.getUsername();//Redis的key
        String time = redisUtil.getUniqueId();//获取redis全局唯一ID
        Session session = SecurityUtils.getSubject().getSession();//在session当中写入用户
        session.setAttribute("profile", profile);
        session.setAttribute("time" + profile.getEmail(), time);//在session写入当前用户的登录时间
        redisUtil.set(key, time);//Redis写入时间
        redisUtil.expire(key, 6000);//设置过期时间
    }

    public String getTime() {
        Date date = new Date();//创建时间
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-ddhh:mm:ss");// 格式化时间中间不能有空格
        return format.format(date);
    }

    public String setKeyOnCookieAndRedis() {
        String time = redisUtil.getUniqueId();//获取redis全局唯一ID
        //随机生成密钥
        String key = RandomStringUtils.getRandomString();
        redisUtil.set("key:" + time, key);
        redisUtil.expire("key:" + time, 60 * 60 * 24 * 7);
        Cookie cookie = new Cookie("time", time);
        cookie.setPath("/");
        cookie.setMaxAge(60 * 60 * 24 * 7);
        response.addCookie(cookie);
        return key;
    }
}

